package com.genius.reservation.common.aspect;

import com.alibaba.fastjson.JSONObject;
import com.genius.reservation.tools.annotation.webLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;


@Slf4j
@Aspect
@Component
public class ReservationLogAspect {

    private final static Logger logger = LoggerFactory.getLogger(ReservationLogAspect.class);
    @Pointcut("@annotation(com.genius.reservation.tools.annotation.webLog)")
    public void webLog(){

    }
    @Before("webLog()")
    public void before(JoinPoint joinPoint) throws Throwable {
        // 得到 HttpServletRequest
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        logger.info("============ before ==========");
        // 获取WebLog注解信息
        String info = getWebLogInfo(joinPoint);

        logger.info("切点信息    : {}", info);
        // 请求地址URL
        logger.info("访问网址	: {}", request.getRequestURL().toString());
        // 请求方法
        logger.info("访问方法 : {}", request.getMethod());
        // 具体切入执行方法
        logger.info("执行方法 : {}.{}", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName());
        // 请求IP
        logger.info("请求IP : {}", request.getRemoteAddr());// 打印描述信息
        // 请求参数
        logger.info("请求参数 : {}", Arrays.asList(joinPoint.getArgs()));

        logger.info("请求Body : {}", JSONObject.toJSONString(request.getParameterNames()));

    }

    @After(value = "webLog()")
    public void after(JoinPoint jp) {
        String name = jp.getSignature().getName();
        log.debug("{}方法执行结束...",name);
    }
    @AfterReturning(value = "webLog()")
    public void afterReturning(JoinPoint jp) {
        String name = jp.getSignature().getName();
        log.debug("{}方法执行成功",name);
    }

    @AfterThrowing(value = "webLog()", throwing = "e")
    public void afterThrowing(JoinPoint jp, Exception e) {
        String name = jp.getSignature().getName();
        log.debug("{}方法抛异常,异常是{}",name , e.getMessage());
    }

    @Around("webLog()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        String name = pjp.getSignature().getName();
        // 统计方法执行时间
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        long end = System.currentTimeMillis();
        System.out.println(name + "方法执行时间为：" + (end - start) + " ms");
        return result;
    }


    public String getWebLogInfo(JoinPoint joinPoint) throws Exception {
        // 获取切入点的目标类
        String targetName = joinPoint.getTarget().getClass().getName();
        Class<?> targetClass = Class.forName(targetName);
        // 获取切入方法名
        String methodName = joinPoint.getSignature().getName();
        // 获取切入方法参数
        Object[] arguments = joinPoint.getArgs();
        // 获取目标类的所有方法
        Method[] methods = targetClass.getMethods();
        for (Method method : methods) {
            // 方法名相同、包含目标注解、方法参数个数相同（避免有重载）
            if (method.getName().equals(methodName) && method.isAnnotationPresent(webLog.class)
                    && method.getParameterTypes().length == arguments.length) {
                return method.getAnnotation(webLog.class).value();
            }
        }
        return "目标类----->"+targetName+"方法名----->"+methodName+"参数----->"+ Arrays.toString(arguments);
    }


}
